package com.ruoyi.treatment.service.impl;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.ruoyi.medicine.mapper.DocStocksMapper;
import com.ruoyi.treatment.domain.dto.DocTreatmentSubmitDto;
import com.ruoyi.treatment.domain.dto.YaoDanDto;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.ruoyi.treatment.mapper.DocTreatmentMapper;
import com.ruoyi.treatment.domain.DocTreatment;
import com.ruoyi.treatment.service.IDocTreatmentService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 就诊信息Service业务层处理
 *
 * @author ruoyi
 * @date 2025-08-14
 */
@Service
@Slf4j
public class DocTreatmentServiceImpl implements IDocTreatmentService
{
    @Autowired
    private DocTreatmentMapper docTreatmentMapper;

    @Autowired
    private DocStocksMapper docStocksMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询就诊信息
     *
     * @param treatId 就诊信息主键
     * @return 就诊信息
     */
    @Override
    public DocTreatment selectDocTreatmentByTreatId(Long treatId)
    {
        return docTreatmentMapper.selectDocTreatmentByTreatId(treatId);
    }

    /**
     * 查询就诊信息列表
     *
     * @param docTreatment 就诊信息
     * @return 就诊信息
     */
    @Override
    public List<DocTreatment> selectDocTreatmentList(DocTreatment docTreatment,Long userId)
    {
        // 将医生ID设置到params参数中，供MyBatis查询使用
        if (docTreatment.getParams() == null) {
            docTreatment.setParams(new HashMap<>());
        }
        docTreatment.getParams().put("doctorId", userId);
        return docTreatmentMapper.selectDocTreatmentList(docTreatment);
    }

    /**
     * 新增就诊信息
     *
     * @param docTreatment 就诊信息
     * @return 结果
     */
    @Override
    public int insertDocTreatment(DocTreatment docTreatment)
    {
        return docTreatmentMapper.insertDocTreatment(docTreatment);
    }

    /**
     * 修改就诊信息
     *
     * @param docTreatment 就诊信息
     * @return 结果
     */
    @Override
    public int updateDocTreatment(DocTreatment docTreatment)
    {
        return docTreatmentMapper.updateDocTreatment(docTreatment);
    }

    /**
     * 批量删除就诊信息
     *
     * @param treatIds 需要删除的就诊信息主键
     * @return 结果
     */
    @Override
    public int deleteDocTreatmentByTreatIds(Long[] treatIds)
    {
        return docTreatmentMapper.deleteDocTreatmentByTreatIds(treatIds);
    }

    /**
     * 删除就诊信息信息
     *
     * @param treatId 就诊信息主键
     * @return 结果
     */
    @Override
    public int deleteDocTreatmentByTreatId(Long treatId)
    {
        return docTreatmentMapper.deleteDocTreatmentByTreatId(treatId);
    }

    @Autowired
    private RedissonClient redissonClient;
    /**
     * 提交就诊记录
     * @param SubmitDto
     * @return
     */


    /**
     * 提交就诊记录
     * @param SubmitDto
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int submitMedicine(DocTreatmentSubmitDto SubmitDto) throws Exception {
        // 创建Redisson分布式锁，使用treatId作为锁的标识确保同一就诊记录不会被并发处理
        RLock lock = redissonClient.getLock("submit_medicine_lock:" + SubmitDto.getTreatId());
        try {
            // 尝试获取锁，等待时间为3秒，持有锁时间为30秒
            // 如果超过3秒没有获取到锁，就直接返回失败
            boolean isLocked = lock.tryLock(3, 30, TimeUnit.SECONDS);
            if (!isLocked) {
                log.warn("获取锁失败，就诊记录ID: {}", SubmitDto.getTreatId());
                throw new Exception("系统繁忙，请稍后重试");
            }

            log.info("成功获取锁，开始处理就诊记录，ID: {}", SubmitDto.getTreatId());

            // 生成药方ID
            String prescriptId = generatePrescriptId();
            Date treatTime = new Date();

            // 使用dto中的数据和生成的prescriptId创建治疗记录
            DocTreatment treatment = new DocTreatment();

            treatment.setTreatId(SubmitDto.getTreatId()); // 从DTO中获取treatId
            treatment.setNickName(SubmitDto.getNickName());
            treatment.setUserName(SubmitDto.getUserName());
            treatment.setUserAge(SubmitDto.getUserAge());
            treatment.setAppAddress(SubmitDto.getAppAddress());
            treatment.setTreatInfo(SubmitDto.getTreatInfo());
            treatment.setPrescriptId(prescriptId);
            treatment.setTreatState("已就诊"); // 设置就诊状态为已就诊

            treatment.setTreatTime(treatTime);

            int result = docTreatmentMapper.updateDocTreatment(treatment);

            // 处理药品清单
            if (SubmitDto.getYaoDan() != null && !SubmitDto.getYaoDan().isEmpty()) {
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("prescriptId", prescriptId);
                paramMap.put("list", SubmitDto.getYaoDan());
                docTreatmentMapper.insertMedicineMessager(paramMap);

                // 扣减药品库存
                for (DocTreatmentSubmitDto.YaoDanDto yaoDanDto : SubmitDto.getYaoDan()) {
                    int updateResult = docStocksMapper.reduceDrugInventory(yaoDanDto.getDrugId(), yaoDanDto.getQuantity());

                    // 如果更新结果为0，说明库存不足
                    if (updateResult == 0) {
                        // 关键：确保异常被正确抛出以触发事务回滚
                        throw new Exception("药品ID为 " + yaoDanDto.getDrugId() + " 的库存不足，无法完成扣减操作");
                    }
                }
            }

            // 清除所有药品相关缓存
            clearAllMedicineCaches();

            log.info("就诊记录处理完成，ID: {}", SubmitDto.getTreatId());
            return result;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("获取锁被中断，就诊记录ID: {}", SubmitDto.getTreatId(), e);
            throw new Exception("系统繁忙，请稍后重试");
        } catch (Exception e) {
            log.error("处理就诊记录时发生异常，ID: {}", SubmitDto.getTreatId(), e);
            // 关键：重新抛出异常以确保事务回滚
            throw e;
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
                log.info("释放锁成功，就诊记录ID: {}", SubmitDto.getTreatId());
            }
        }
    }

    /**
     * 清除所有药品相关缓存
     */
    private void clearAllMedicineCaches() {
        try {
            // 清除所有药品库存相关缓存
            Set<String> medicineKeys = redisTemplate.keys("medicine_stocks_*");
            if (medicineKeys != null && !medicineKeys.isEmpty()) {
                redisTemplate.delete(medicineKeys);
            }

            log.info("已清除所有药品相关缓存");
        } catch (Exception e) {
            log.error("清除药品缓存时发生异常: {}", e.getMessage());
        }
    }

    @Override
    public List<YaoDanDto> selectYaoDanByPrescriptId(String prescriptionId) {
        return docTreatmentMapper.selectYaoDanByPrescriptId(prescriptionId);
    }

    private String generatePrescriptId() {
        // 获取当前时间戳
        long timestamp = System.currentTimeMillis();
        // 生成随机数
        int random = new Random().nextInt(10000);
        // 组合生成唯一ID，格式：RX + 年月日 + 时间戳后4位 + 4位随机数
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        String dateStr = sdf.format(new Date());
        return "RX" + dateStr + String.valueOf(timestamp).substring(String.valueOf(timestamp).length() - 4) +
                String.format("%04d", random);
    }
}
